﻿/**
 * Copyright (C) 2004-2009 D3Systems, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net.Sockets;


namespace OMGServer
{
    class SocketPacket
    {
        public System.Net.Sockets.Socket clientSocket;
        public byte[] dataBuffer = new byte[1];

        // Event Logger for Debugging Purposes
        System.Diagnostics.EventLog logger;

        AsyncCallback asynDisconnect = null;

        OMGProtocol.XmlLightWeightParser parser;

        /// <summary>
        /// Constructor.
        /// </summary>
        public SocketPacket(EventLog logger, AsyncCallback asynDisconnect)
        {
            this.logger = logger;
            this.asynDisconnect = asynDisconnect;

            parser = new OMGProtocol.XmlLightWeightParser(logger);
        }

        /// <summary>
        /// Method that intitializes and prepares for more incoming data.
        /// </summary>
        public void WaitForData()
        {
            try
            {
                clientSocket.BeginReceive(dataBuffer, 0, dataBuffer.Length,
                    SocketFlags.None, new AsyncCallback(onDataReceived), this);
            }
            catch (SocketException se) {
                logger.WriteEntry("Socket Exception: " + se.Message);
            }
            catch (Exception ex)
            {
                logger.WriteEntry("Error Waiting For Data: " + ex.Message);
            }
        }

        /// <summary>
        /// Callback method called when data has been received from the client socket.
        /// </summary>
        private void onDataReceived(IAsyncResult ar)
        {

            Boolean disconnecting = false;

            try
            {
                SocketPacket socketData = (SocketPacket)ar.AsyncState;

                //end receive...
                int iRx = 0;
                iRx = clientSocket.EndReceive(ar);

                if (iRx > 0)
                {
                    char[] chars = new char[iRx + 1];

                    System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
                    int charLen = d.GetChars(dataBuffer, 0, iRx, chars, 0);

                    String szData = new String(chars);

                    // Parse as many stanzas as possible from the received data
                    parser.read(dataBuffer);

                    if (parser.areThereMsgs()) {
                        foreach (String stanza in parser.getMsgs()) {
                            logger.WriteEntry("Received XML: " + stanza);
                        }
                    }
                }
                else
                {
                    disconnecting = true;
                    clientSocket.BeginDisconnect(false, asynDisconnect, this);
                }
                
            }
            catch (ObjectDisposedException ex)
            {
                logger.WriteEntry("ObjectDisposedException: " + ex.Message);
            }
            catch (SocketException se)
            {
                logger.WriteEntry("Socket Exception: " + se.Message);
            }
            catch (Exception ex)
            {
                logger.WriteEntry("Error Receiving Data: " + ex.Message);
            }

            if (!disconnecting && clientSocket.Connected)
                WaitForData();
            else
                logger.WriteEntry("Client has disconnected: " + clientSocket.AddressFamily.ToString());
        }
    }
}
